package com.coincalf.wallet.task.collect;

import com.coincalf.framework.enums.RechargeStatus;
import com.coincalf.framework.utils.DateUtil;
import com.coincalf.wallet.blockchain.client.Web3jSingleton;
import com.coincalf.wallet.entity.CoinRecharge;
import com.coincalf.wallet.service.CoinRechargeService;
import com.coincalf.wallet.service.CollectCoinRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.web3j.protocol.core.DefaultBlockParameterName;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;

@Slf4j
@Component
@EnableScheduling
public class CollectCoins {

    @Autowired
    private CoinRechargeService coinRechargeService;
    @Autowired
    private CollectCoinRecordService collectCoinRecordService;

    //归集手续费地址,即提供手续费的地址 ETH TRX这些
    @Value("${blockchain.eth.fee.address}")
    public String ethCollectFeeAddress;//ETH手续费地址


    /**
     * ETH归集任务 每小时执行一次
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void collectEth() {
        log.info("开始执行ETH归集任务 当前时间={}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        /**
         * 查询用户充币记录
         * 查询用户当前链上余额
         * 进行归集操作
         */
        List<CoinRecharge> coinRecharges = coinRechargeService.findAllByAndCoinNameAndTxStatusAndCollected(
                "ETH", RechargeStatus.SUCCESS.getCode(), 0
        );
        for (CoinRecharge c : coinRecharges) {
            String txId = collectCoinRecordService.collectEth(c);
            if (StringUtils.isNotBlank(txId)) {
                log.warn("本次ETH归集成功 from={} amount={} txId={}",
                        c.getAddress(), c.getMum(), txId
                );
            }
        }
    }

    /**
     * USDT_ERC20归集任务
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void collectUsdtErc20() {
        log.info("开始执行USDT_ERC20归集任务 当前时间={}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        //归集之前查询手续费地址是否有多交易未确认，如果有，则暂时不进行归集
        String feeAddress = this.ethCollectFeeAddress;
        try {
            BigInteger nonce1 = Web3jSingleton.getWeb3j().ethGetTransactionCount(feeAddress, DefaultBlockParameterName.LATEST).send().getTransactionCount();
            BigInteger nonce2 = Web3jSingleton.getWeb3j().ethGetTransactionCount(feeAddress, DefaultBlockParameterName.PENDING).send().getTransactionCount();
            long pending = nonce2.longValue() - nonce1.longValue();
            if (pending > 0) {
                log.info("手续费地址有{}笔交易未确认，等待确认之后再执行归集操作...", pending);
                return;
            }
        } catch (Exception e) {
            log.warn("手续费地址交易状态获取失败 feeAddress={} e={} ", feeAddress, e);
            return;
        }

        log.info("开始执行USDT_ERC20归集任务 当前时间={}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));

        /**
         * 归集思路，查询地址ETH余额，不够手续费则补上，否则不做处理等待归集USDT
         * 如果地址没有ETH 则先转ETH到该地址，然后再从该地址转USDT到归集地址
         */
        //从用户充币纪录中选择归集：未进行归集，交易已成功，币种是USDT_ERC20
        List<CoinRecharge> coinRecharges = coinRechargeService.findAllByAndCoinNameAndTxStatusAndCollected(
                "USDT_ERC20",
                RechargeStatus.SUCCESS.getCode(),
                0
        );
        collectCoinRecordService.collectUsdtErc20(coinRecharges);
    }

    /**
     * 每小时执行一次 BTC归集操作
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    public void collectBtcMany2One() {
        log.info("开始执行BTC归集任务 当前时间={}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        /**
         * 查询用户充币记录
         * 查询用户当前链上余额
         * 进行归集操作
         */
        List<CoinRecharge> coinRecharges = coinRechargeService.findAllByAndCoinNameAndTxStatusAndCollected(
                "BTC",
                RechargeStatus.SUCCESS.getCode(),
                0
        );
        for (CoinRecharge c : coinRecharges) {
            String txId = collectCoinRecordService.collectBtc(c);
            if (StringUtils.isNotBlank(txId)) {
                log.warn("本次BTC归集成功 from={} amount={} txId={}",
                        c.getAddress(), c.getMum(), txId
                );
            }
        }
    }

    /**
     * 每0.5小时执行一次
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void collectUsdtOmni() {
        log.info("开始执行USDT_OMNI归集任务 当前时间={}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        /**
         * 查询用户充币记录
         * 查询用户当前链上余额
         * 进行归集操作
         */
        List<CoinRecharge> coinRecharges = coinRechargeService.findAllByAndCoinNameAndTxStatusAndCollected(
                "USDT_OMNI",
                RechargeStatus.SUCCESS.getCode(),
                0
        );
        for (CoinRecharge c : coinRecharges) {
            String txId = collectCoinRecordService.collectUsdtOmni(c);
            if (StringUtils.isNotBlank(txId)) {
                log.warn("本次USDT_OMNI归集成功 from={} txId={}",
                        c.getAddress(), txId
                );
            }
        }
    }

}
